Skip to content

Python脚本我设定了是直接生成的8进制(1个字节——0xff)的数组,而image2cpp则是生成的16进制(2字节——0xffff)格式的数组,这两种输出格式的差异其实本质是一样的,只是数据表示的粒度不同。8进制不用再切割,因为SPI单次就是发送8bit的数据,16进制在发送前还要再切割一遍,且MSB与LSB字节序的问题要仔细检查。

🔍 核心解释

  • image2cpp 输出:每个像素用一个 16 位整数(如 0xebef)表示,也就是两个字节合并为一个数。
  • Python 脚本输出:每个像素拆成 两个独立的 8 位字节(如 0xEB, 0xEF),分开存放。

相同点:颜色值完全一致,都是 RGB565 格式。
不同点:image2cpp 是 压缩的数组(每个元素占2字节),Python脚本是 展开的字节流(每个像素占2个数组元素)。

🧩 在 ESP32-S3 中发送图片需要什么?

ST7789 通过 SPI 接收数据,SPI 一次发送一个字节(8位)。
所以,不管你用哪种格式存储,最终发送时都要 按字节顺序 发送(高字节在前,低字节在后)。

方案一:使用 Python 脚本生成的 uint8_t image_data[](推荐)

因为已经是字节数组,可以直接用 spi_device_transmit 发送,无需额外处理:

c
extern const uint8_t image_data[];
spi_transaction_t trans = {
    .tx_buffer = image_data,
    .length = 240 * 320 * 2 * 8,   // 总位数
};
spi_device_transmit(spi, &trans);

优点:直接匹配 SPI 发送需求,无需转换。

方案二:使用 image2cpp 生成的 uint16_t 数组

如果要使用 uint16_t 数组,必须将其转换为字节流才能发送。有以下两种处理方式:

方式 A:发送前实时拆包(不推荐,增加CPU开销)

c
const uint16_t *img16 = ...;
for (int i=0; i<240*320; i++) {
    uint16_t pixel = img16[i];
    st7789_write_data(pixel >> 8, spi);   // 高字节
    st7789_write_data(pixel & 0xFF, spi); // 低字节
}

这会逐像素发送,速度慢。

方式 B:用 uint16_t 数组直接发送(需注意字节序)

如果你的平台是 小端模式(ESP32-S3 默认),uint16_t 数组在内存中的存储顺序是 低字节在前,而 ST7789 期望 高字节在前
直接发送会导致颜色错乱。需要提前调整字节序,或者用 spi_transactiontx_bufferuint8_t* 转换。

更简单的做法:将 image2cpp 的输出转换为字节数组
你可以修改 image2cpp 的输出设置,选择 “数组格式为字节(byte)”,或者用 Python 脚本自动转换。

🛠️ 如何将 image2cpp 的输出转换为字节数组(Python 脚本)

如果你已经有了 image2cpp 的 uint16_t 格式数据,可以用下面的 Python 脚本拆成字节:

python
# 假设你的 image2cpp 输出存为 img16.h,内容为 const uint16_t img[] = { ... };
# 读取并转换为字节数组
with open("img16.h", "r") as f:
    content = f.read()
    # 提取大括号内的十六进制数
    import re
    hex_nums = re.findall(r'0x[0-9A-Fa-f]+', content)
    nums = [int(h, 16) for h in hex_nums]  # 每个数都是16位

# 转为字节数组(高字节在前)
byte_data = []
for val in nums:
    byte_data.append((val >> 8) & 0xFF)
    byte_data.append(val & 0xFF)

# 写入 image.h
with open("image.h", "w") as f:
    f.write("const uint8_t image_data[] = {\n")
    for i, b in enumerate(byte_data):
        f.write(f"0x{b:02X}, ")
        if (i+1) % 32 == 0:
            f.write("\n")
    f.write("};\n")

运行后,生成的就是可以直接发送的字节数组。

📌 总结建议

  • 推荐使用 Python 脚本(你之前展示的那个),直接生成 uint8_t 字节数组,省去转换步骤。
  • 如果已经用 image2cpp 生成,可以运行上面的转换脚本,或者直接在 image2cpp 的设置里选择 “Output format: C array (byte)”,它会自动拆成字节。

现在,你的 image_data 就是 uint8_t 数组,可以用 lcd_display_image_dma 直接发送了。颜色顺序(高字节在前)也已匹配。 😊

觉醒,然后燎原。 © 2026 门主引擎